社论 22.10.15 排列逆序对计数

之前对着第二维就是求和生成然后什么玩意都搞不出来 wssb


给定 n,k,求长度为 n 、逆序对数为 k 的排列数量模 998244353 后的值。

n,k3000

考虑令 fi,j 为长度为 i,逆序对数为 j 的排列的数量。答案即为 fn,k

考虑通过插入计数。
我们首先有一个长度为 i,逆序对数为 j 的排列。现在向其中插入元素 i+1。容易发现其插入在从前往后数的第 k 位置会导致其后面的 (ik+1) 个元素和它生成逆序对,因此 fi,j 能贡献给 fi+1,j+ik+1 s.t. 0ki
重写一下,我们有 dp 式:

fi,j=k=0i1fi1,jk

然后能做到 O(n2k) 的复杂度。

我们发现后面的部分其实是一个前缀和差分的形式,因此维护一下前缀和能做到 O(nklogn)O(nk) 的复杂度。

O(nk log n)
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
#define rep(i,a,b) for (register int i = (a), i##_ = (b) + 1; i < i##_; ++i)
#define pre(i,a,b) for (register int i = (a), i##_ = (b) - 1; i > i##_; --i)
int n, m, x;

struct BIT {
    int Index[3005];
    int operator [] (int p) {
        int ret = 0;
        while (p) {
            ret += Index[p];
            p ^= p & -p;
        } return ret;
    }
    void add(int p, int v) {
        while (p <= n) {
            Index[p] += v;
            p += p & -p;
        }
    }
} f[3005];

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    f[1].add(1, 1);
    rep(i,2,n) {
        rep(j,0,min((i * (i-1)) >> 1, n)) {
            f[i].add(j + 1, (f[i-1][j + 1] - f[i-1][j - min(i-1,j)]));
        }
    } rep(i,1,m) {
        cin >> x; x ++;
        cout << (f[n][x] - f[n][x-1]) << '\n';
    }
}



[能不能再给力一点啊?]

题面相同。

n,k105

认为 n,k 同阶,因此下文中渐进式内只使用 n

考虑对第二维求和得到生成函数

Fi(x)=j=1fi,j xj

则答案即为 [xk]Fn(x)

我们考虑转移方程。我们发现,j 位置能够从 j1ji+1 转移过来。放在生成函数上,Fi(x) 可以通过 Fi1(x)xi1×Fi1(x) 转移过来。
于是有

Fn(x)=(i=0n1xi)Fn1(x)=(1xn1x)Fn1(x)=i=1n1xi1x=(i=1n1xi)(1x)n

考虑 f(x)=i=1n(1xi)g(x)=(1x)n 的求法。

f(x) 是五边形数。有关五边形数:

五边形数定理  (Euler)

Φ(x) 为欧拉函数的生成函数。有下式:

Φ(x)=i=1n(1xi)=i=0(1)ixi(3i±1)2

我们发现 f(x) 的幂级数形式只有 O(n) 项有值。直接生成即可。这部分的复杂度为 O(n)

g(x) 可以直接通过多项式快速幂在 O(nlogn) 的复杂度内生成。

生成后直接做多项式卷积即可。复杂度 O(nlogn)



[能不能再给力一点啊?]

题面相同。

k105,n1018

注意到在上文中我们只需要多项式中第 k 次项。因此直接从 k 位置截断即可得到最终答案。

随后我们可以在 O(k) 的时间内生成 f
随后我们可以使用多项式快速幂得到 g

时间复杂度为 O(klogk)



使用生成函数方式证明 f 的行取值对称。

F(1x)=i=1n1(1x)i11x= i=1n11xi11x= i=1nxi1xixx1= i=1nxi1xi1(x1)

于是有

F(x)F(1x)=i=1n1xi1xxi1(x1)xi1=i=1nxi1=xn(n1)2

于是有

F(x)=[xk]F(1x)xn(n1)2= [xkn(n1)2]F(1x)= [xn(n1)2k]F(x)

由于 F(x) 有意义的取值部分位于 x0xn(n1)2 部分,因此我们证明了 fn,i 的取值的对称性。



关于“能不能再给力一点啊?”这件事,由于我多项式远处系数提取的功底不够扎实,先咕着。

posted @   joke3579  阅读(111)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示